#include "sqltextedit.h"
#include <QPainter>
#include <QTextBlock>
#include <QScrollBar>
#include <QApplication>
#include <QPainterPath>
#include <QMouseEvent>
#include <QToolTip>
#include <QRegularExpression>

SqlTextEdit::SqlTextEdit(QWidget *parent)
    : QPlainTextEdit(parent)
{
    lineNumberArea = new LineNumberArea(this);
    
    connect(this, &SqlTextEdit::blockCountChanged, this, &SqlTextEdit::updateLineNumberAreaWidth);
    connect(this, &SqlTextEdit::updateRequest, this, &SqlTextEdit::updateLineNumberArea);
    connect(this, &SqlTextEdit::cursorPositionChanged, this, &SqlTextEdit::highlightCurrentLine);
    
    updateLineNumberAreaWidth(0);
    highlightCurrentLine();
    
    // 设置默认字体
    QFont font("Courier New", 10);
    setFont(font);
}

void SqlTextEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    QPainter painter(lineNumberArea);
    painter.fillRect(event->rect(), QColor(Qt::lightGray).lighter(120));

    QTextBlock block = firstVisibleBlock();
    int blockNumber = block.blockNumber();
    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
    int bottom = top + qRound(blockBoundingRect(block).height());

    while (block.isValid() && top <= event->rect().bottom()) {
        if (block.isVisible() && bottom >= event->rect().top()) {
            QString number = QString::number(blockNumber + 1);
            
            // 绘制折叠指示器
            if (isFoldableBlock(block)) {
                QRect foldRect(0, top, lineNumberArea->width(), fontMetrics().height());
                painter.setPen(Qt::black);
                
                // 绘制折叠/展开图标
                QPainterPath path;
                int iconSize = 8;
                int iconX = 2;
                int iconY = top + (fontMetrics().height() - iconSize) / 2;
                
                if (foldedBlocks.contains(blockNumber)) {
                    // 绘制展开图标 (+)
                    path.moveTo(iconX, iconY + iconSize/2);
                    path.lineTo(iconX + iconSize, iconY + iconSize/2);
                    path.moveTo(iconX + iconSize/2, iconY);
                    path.lineTo(iconX + iconSize/2, iconY + iconSize);
                } else {
                    // 绘制折叠图标 (-)
                    path.moveTo(iconX, iconY + iconSize/2);
                    path.lineTo(iconX + iconSize, iconY + iconSize/2);
                }
                
                painter.drawPath(path);
            }
            
            // 绘制行号
            painter.setPen(Qt::black);
            painter.drawText(15, top, lineNumberArea->width() - 20, fontMetrics().height(),
                             Qt::AlignRight, number);
        }

        block = block.next();
        top = bottom;
        bottom = top + qRound(blockBoundingRect(block).height());
        ++blockNumber;
    }
}

int SqlTextEdit::lineNumberAreaWidth()
{
    int digits = 1;
    int max = qMax(1, blockCount());
    while (max >= 10) {
        max /= 10;
        ++digits;
    }

    int space = 20 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
    return space;
}

void SqlTextEdit::resizeEvent(QResizeEvent *event)
{
    QPlainTextEdit::resizeEvent(event);

    QRect cr = contentsRect();
    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

void SqlTextEdit::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_F3 && e->modifiers() & Qt::ControlModifier) {
        toggleBlockFold();
        return;
    }
    
    QPlainTextEdit::keyPressEvent(e);
}

void SqlTextEdit::updateLineNumberAreaWidth(int /* newBlockCount */)
{
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}

void SqlTextEdit::highlightCurrentLine()
{
    QList<QTextEdit::ExtraSelection> extraSelections;

    if (!isReadOnly()) {
        QTextEdit::ExtraSelection selection;

        QColor lineColor = QColor(Qt::yellow).lighter(160);

        selection.format.setBackground(lineColor);
        selection.format.setProperty(QTextFormat::FullWidthSelection, true);
        selection.cursor = textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);
    }

    setExtraSelections(extraSelections);
}

void SqlTextEdit::updateLineNumberArea(const QRect &rect, int dy)
{
    if (dy)
        lineNumberArea->scroll(0, dy);
    else
        lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());

    if (rect.contains(viewport()->rect()))
        updateLineNumberAreaWidth(0);
}

void SqlTextEdit::toggleBlockFold()
{
    QTextBlock block = textCursor().block();
    int blockNumber = block.blockNumber();
    
    if (isFoldableBlock(block)) {
        if (foldedBlocks.contains(blockNumber)) {
            unfoldBlock(blockNumber);
        } else {
            foldBlock(blockNumber);
        }
    }
}

void SqlTextEdit::foldCurrentBlock()
{
    QTextBlock block = textCursor().block();
    int blockNumber = block.blockNumber();
    
    if (isFoldableBlock(block) && !foldedBlocks.contains(blockNumber)) {
        foldBlock(blockNumber);
    }
}

void SqlTextEdit::unfoldCurrentBlock()
{
    QTextBlock block = textCursor().block();
    int blockNumber = block.blockNumber();
    
    if (isFoldableBlock(block) && foldedBlocks.contains(blockNumber)) {
        unfoldBlock(blockNumber);
    }
}

bool SqlTextEdit::isFoldableBlock(const QTextBlock &block) const
{
    QString text = block.text().trimmed().toUpper();
    
    // 检查是否是可折叠的SQL块开头
    return text.startsWith("SELECT") || 
           text.startsWith("INSERT") || 
           text.startsWith("UPDATE") || 
           text.startsWith("DELETE") || 
           text.startsWith("CREATE") || 
           text.startsWith("ALTER") || 
           text.startsWith("DROP") ||
           text.startsWith("BEGIN") ||
           text.startsWith("WITH");
}

int SqlTextEdit::findBlockEnd(const QTextBlock &startBlock) const
{
    QTextBlock block = startBlock.next();
    int level = 1;
    
    while (block.isValid()) {
        QString text = block.text().trimmed().toUpper();
        
        // 检查是否有嵌套的可折叠块
        if (isFoldableBlock(block)) {
            level++;
        }
        
        // 检查块结束标记
        if (text.endsWith(";") || 
            text.startsWith("END") || 
            text.startsWith("COMMIT") || 
            text.startsWith("ROLLBACK")) {
            level--;
            if (level <= 0) {
                return block.blockNumber();
            }
        }
        
        block = block.next();
    }
    
    return -1; // 未找到结束
}

void SqlTextEdit::foldBlock(int blockNumber)
{
    QTextBlock startBlock = document()->findBlockByNumber(blockNumber);
    int endBlockNumber = findBlockEnd(startBlock);
    
    if (endBlockNumber > blockNumber) {
        // 标记为已折叠
        foldedBlocks[blockNumber] = true;
        
        // 隐藏范围内的行
        QTextBlock block = startBlock.next();
        while (block.isValid() && block.blockNumber() <= endBlockNumber) {
            block.setVisible(false);
            block = block.next();
        }
        
        // 更新显示
        document()->markContentsDirty(startBlock.position(), 
                                     block.position() - startBlock.position());
        updateLineNumberArea(viewport()->rect(), 0);
        update();
    }
}

void SqlTextEdit::unfoldBlock(int blockNumber)
{
    if (!foldedBlocks.contains(blockNumber)) {
        return;
    }
    
    QTextBlock startBlock = document()->findBlockByNumber(blockNumber);
    int endBlockNumber = findBlockEnd(startBlock);
    
    if (endBlockNumber > blockNumber) {
        // 取消标记为已折叠
        foldedBlocks.remove(blockNumber);
        
        // 显示范围内的行
        QTextBlock block = startBlock.next();
        while (block.isValid() && block.blockNumber() <= endBlockNumber) {
            block.setVisible(true);
            block = block.next();
        }
        
        // 更新显示
        document()->markContentsDirty(startBlock.position(), 
                                     block.position() - startBlock.position());
        updateLineNumberArea(viewport()->rect(), 0);
        update();
    }
}

void SqlTextEdit::updateFoldIndicator(int blockNumber)
{
    // 更新折叠指示器显示
    QTextBlock block = document()->findBlockByNumber(blockNumber);
    if (block.isValid()) {
        QRect rect = blockBoundingGeometry(block).toRect();
        lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
    }
}

void LineNumberArea::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        // 计算点击的行号
        int y = event->pos().y();
        int blockNumber = codeEditor->cursorForPosition(QPoint(0, y)).blockNumber();
        
        QTextBlock block = codeEditor->document()->findBlockByNumber(blockNumber);
        if (codeEditor->isFoldableBlock(block)) {
            // 切换折叠状态
            if (codeEditor->foldedBlocks.contains(blockNumber)) {
                codeEditor->unfoldBlock(blockNumber);
            } else {
                codeEditor->foldBlock(blockNumber);
            }
            return;
        }
    }
    
    QWidget::mousePressEvent(event);
}